#include "GeometryFactory.h"

//----------------------------------------------------------------------------------------------
GeometryFactory::GeometryFactory() :  m_hr(0)
{ }

//----------------------------------------------------------------------------------------------
GeometryFactory::~GeometryFactory()
{ }

//----------------------------------------------------------------------------------------------
ID3D11Buffer* GeometryFactory::create_box_vb(ID3D11Device* device)
{
	GeometryGenerator::MeshData box;			// struct to store vertices
	m_geoGen.CreateBox(1.0f, 1.0f, 1.0f, box);	// generate vertices
	UINT vertex_count = box.Vertices.size();	// cache vertex count
	
	// Extract the vertex elements we are interested in.
	std::vector<BasicShader::Vertex> vertices(vertex_count);

	unsigned int k = 0;
	for (size_t i = 0; i < vertex_count; ++i, ++k)
	{
		vertices[k].Pos		= box.Vertices[i].Position;
		vertices[k].Normal	= box.Vertices[i].Normal;
		vertices[k].Tex		= box.Vertices[i].TexC;
	}
	
	ID3D11Buffer* pVB;							// vertex buffer to return

	D3D11_BUFFER_DESC vbDesc;
	vbDesc.Usage			= D3D11_USAGE_IMMUTABLE;
	vbDesc.ByteWidth		= sizeof(BasicShader::Vertex) * vertex_count;
	vbDesc.BindFlags		= D3D11_BIND_VERTEX_BUFFER;
	vbDesc.CPUAccessFlags	= 0;
	vbDesc.MiscFlags		= 0;

	D3D11_SUBRESOURCE_DATA vdata;
	vdata.pSysMem = &vertices[0];
	
	m_hr = device->CreateBuffer(&vbDesc, &vdata, &pVB);
	if (FAILED(m_hr))
	{
		DXTRACE_MSG(L"Failed to create box vertex buffer!");
		return false;
	}

	return pVB;
}

//----------------------------------------------------------------------------------------------
ID3D11Buffer* GeometryFactory::create_box_ib(ID3D11Device* device)
{
	GeometryGenerator::MeshData box;			// struct to store indices
	m_geoGen.CreateBox(1.0f, 1.0f, 1.0f, box);	// generate indices
	UINT box_index_count  = box.Indices.size();	// cache index count

	std::vector<UINT> indices;
	indices.insert(indices.end(), box.Indices.begin(), box.Indices.end());
	
	ID3D11Buffer* pIB;							// index buffer to return

	D3D11_BUFFER_DESC ibDesc;
	ibDesc.Usage				= D3D11_USAGE_DEFAULT;
	ibDesc.ByteWidth			= sizeof(UINT) * box_index_count;
	ibDesc.BindFlags			= D3D11_BIND_INDEX_BUFFER;
	ibDesc.CPUAccessFlags		= 0;
	ibDesc.MiscFlags			= 0;
	ibDesc.StructureByteStride	= 0;
	
	D3D11_SUBRESOURCE_DATA idata;
	idata.pSysMem = &indices[0];

	m_hr = device->CreateBuffer(&ibDesc, &idata, &pIB);
	if (FAILED(m_hr))
	{
		DXTRACE_MSG(L"Failed to create box index buffer!");
		return false;
	}

	return pIB;
}

//----------------------------------------------------------------------------------------------
ID3D11Buffer* GeometryFactory::create_sphere_vb(ID3D11Device* device, float radius, UINT sliceCount, UINT stackCount)
{
	GeometryGenerator::MeshData sphere;
	m_geoGen.CreateSphere(radius, sliceCount, stackCount, sphere);
	UINT vertex_count = sphere.Vertices.size(); // Cache vertex count.
	
	// Extract the vertex elements we are interested in.
	std::vector<BasicShader::Vertex> vertices(vertex_count);

	unsigned int k = 0;
	for (size_t i = 0; i < vertex_count; ++i, ++k)
	{
		vertices[k].Pos		= sphere.Vertices[i].Position;
		vertices[k].Normal	= sphere.Vertices[i].Normal;
		vertices[k].Tex		= sphere.Vertices[i].TexC;
	}

	// Create vertex buffer.
	ID3D11Buffer* pVB;

	D3D11_BUFFER_DESC vbDesc;
	vbDesc.Usage			= D3D11_USAGE_IMMUTABLE;
	vbDesc.ByteWidth		= sizeof(BasicShader::Vertex) * vertex_count;
	vbDesc.BindFlags		= D3D11_BIND_VERTEX_BUFFER;
	vbDesc.CPUAccessFlags	= 0;
	vbDesc.MiscFlags		= 0;

	D3D11_SUBRESOURCE_DATA vdata;
	vdata.pSysMem = &vertices[0];

	m_hr = device->CreateBuffer(&vbDesc, &vdata, &pVB);
	if (FAILED(m_hr))
	{
		DXTRACE_MSG(L"Failed to create sphere vertex buffer!");
		return false;
	}

	return pVB;
}

//----------------------------------------------------------------------------------------------
ID3D11Buffer* GeometryFactory::create_sphere_ib(ID3D11Device* device, float radius, UINT sliceCount, UINT stackCount)
{
	GeometryGenerator::MeshData sphere;		   // struct to store indices
	m_geoGen.CreateSphere(radius, sliceCount, stackCount, sphere);
	UINT index_count  = sphere.Indices.size(); // cache index count

	std::vector<UINT> indices;
	indices.insert(indices.end(), sphere.Indices.begin(), sphere.Indices.end());
	
	ID3D11Buffer* pIB;	// index buffer to return

	D3D11_BUFFER_DESC ibDesc;
	ibDesc.Usage				= D3D11_USAGE_DEFAULT;
	ibDesc.ByteWidth			= sizeof(UINT) * index_count;
	ibDesc.BindFlags			= D3D11_BIND_INDEX_BUFFER;
	ibDesc.CPUAccessFlags		= 0;
	ibDesc.MiscFlags			= 0;
	ibDesc.StructureByteStride	= 0;
	
	D3D11_SUBRESOURCE_DATA idata;
	idata.pSysMem = &indices[0];

	m_hr = device->CreateBuffer(&ibDesc, &idata, &pIB);
	if (FAILED(m_hr))
	{
		DXTRACE_MSG(L"Failed to create sphere index buffer!");
		return false;
	}

	return pIB;
}

//----------------------------------------------------------------------------------------------
ID3D11Buffer* GeometryFactory::create_geosphere_vb(ID3D11Device* device, float radius, UINT subdivisions)
{
	GeometryGenerator::MeshData geosphere;
	m_geoGen.CreateGeosphere(radius, subdivisions, geosphere);
	UINT vertex_count = geosphere.Vertices.size();	// cache vertex count

	// Extract the vertex elements we are interested in.
	std::vector<BasicShader::Vertex> vertices(vertex_count);
	unsigned int k = 0;
	for (size_t i = 0; i < vertex_count; ++i, ++k)
	{
		vertices[k].Pos		= geosphere.Vertices[i].Position;
		vertices[k].Normal	= geosphere.Vertices[i].Normal;
		vertices[k].Tex		= geosphere.Vertices[i].TexC;
	}

	// Create vertex buffer.
	ID3D11Buffer* pVB;

	D3D11_BUFFER_DESC vbDesc;
	vbDesc.Usage			= D3D11_USAGE_IMMUTABLE;
	vbDesc.ByteWidth		= sizeof(BasicShader::Vertex) * vertex_count;
	vbDesc.BindFlags		= D3D11_BIND_VERTEX_BUFFER;
	vbDesc.CPUAccessFlags	= 0;
	vbDesc.MiscFlags		= 0;
	vbDesc.StructureByteStride = 0;

	D3D11_SUBRESOURCE_DATA vbData;
	vbData.pSysMem = &vertices[0];

	m_hr = device->CreateBuffer(&vbDesc, &vbData, &pVB);
	if (FAILED(m_hr))
	{
		DXTRACE_MSG(L"Failed to create geosphere vertex buffer!");
		return false;
	}

	return pVB;
}

//----------------------------------------------------------------------------------------------
ID3D11Buffer* GeometryFactory::create_geosphere_ib(ID3D11Device* device, float radius, UINT subdivisions)
{
	GeometryGenerator::MeshData geosphere;			// struct to store indices
	m_geoGen.CreateGeosphere(radius, subdivisions, geosphere);
	UINT index_count  = geosphere.Indices.size();	// cache index count

	std::vector<UINT> indices;
	indices.insert(indices.end(), geosphere.Indices.begin(), geosphere.Indices.end());
	
	ID3D11Buffer* pIB;								// index buffer to return

	D3D11_BUFFER_DESC ibDesc;
	ibDesc.Usage				= D3D11_USAGE_DEFAULT;
	ibDesc.ByteWidth			= sizeof(UINT) * index_count;
	ibDesc.BindFlags			= D3D11_BIND_INDEX_BUFFER;
	ibDesc.CPUAccessFlags		= 0;
	ibDesc.MiscFlags			= 0;
	ibDesc.StructureByteStride	= 0;
	
	D3D11_SUBRESOURCE_DATA idata;
	idata.pSysMem = &indices[0];

	m_hr = device->CreateBuffer(&ibDesc, &idata, &pIB);
	if (FAILED(m_hr))
	{
		DXTRACE_MSG(L"Failed to create geosphere index buffer!");
		return false;
	}

	return pIB;
}

//----------------------------------------------------------------------------------------------
ID3D11Buffer* GeometryFactory::create_cylinder_vb(ID3D11Device* device, float bottomRadius, float topRadius, float height, UINT sliceCount, UINT stackCount)
{
	GeometryGenerator::MeshData cylinder;
	m_geoGen.CreateCylinder(bottomRadius, topRadius, height, sliceCount, stackCount, cylinder);
	UINT vertex_count = cylinder.Vertices.size();	// cache vertex count

	// Extract the vertex elements we are interested in.
	std::vector<BasicShader::Vertex> vertices(vertex_count);
	unsigned int k = 0;
	for (size_t i = 0; i < vertex_count; ++i, ++k)
	{
		vertices[k].Pos		= cylinder.Vertices[i].Position;
		vertices[k].Normal	= cylinder.Vertices[i].Normal;
		vertices[k].Tex		= cylinder.Vertices[i].TexC;
	}

	// Create vertex buffer.
	ID3D11Buffer* pVB;

	D3D11_BUFFER_DESC vbDesc;
	vbDesc.Usage			= D3D11_USAGE_IMMUTABLE;
	vbDesc.ByteWidth		= sizeof(BasicShader::Vertex) * vertex_count;
	vbDesc.BindFlags		= D3D11_BIND_VERTEX_BUFFER;
	vbDesc.CPUAccessFlags	= 0;
	vbDesc.MiscFlags		= 0;
	vbDesc.StructureByteStride = 0;

	D3D11_SUBRESOURCE_DATA vbData;
	vbData.pSysMem = &vertices[0];

	m_hr = device->CreateBuffer(&vbDesc, &vbData, &pVB);
	if (FAILED(m_hr))
	{
		DXTRACE_MSG(L"Failed to create cylinder vertex buffer!");
		return false;
	}

	return pVB;
}

//----------------------------------------------------------------------------------------------
ID3D11Buffer* GeometryFactory::create_cylinder_ib(ID3D11Device* device, float bottomRadius, float topRadius, float height, UINT sliceCount, UINT stackCount)
{
	GeometryGenerator::MeshData cylinder;			// struct to store indices
	m_geoGen.CreateCylinder(bottomRadius, topRadius, height, sliceCount, stackCount, cylinder);
	UINT index_count  = cylinder.Indices.size();	// cache index count

	std::vector<UINT> indices;
	indices.insert(indices.end(), cylinder.Indices.begin(), cylinder.Indices.end());
	
	ID3D11Buffer* pIB;								// index buffer to return

	D3D11_BUFFER_DESC ibDesc;
	ibDesc.Usage				= D3D11_USAGE_DEFAULT;
	ibDesc.ByteWidth			= sizeof(UINT) * index_count;
	ibDesc.BindFlags			= D3D11_BIND_INDEX_BUFFER;
	ibDesc.CPUAccessFlags		= 0;
	ibDesc.MiscFlags			= 0;
	ibDesc.StructureByteStride	= 0;
	
	D3D11_SUBRESOURCE_DATA idata;
	idata.pSysMem = &indices[0];

	m_hr = device->CreateBuffer(&ibDesc, &idata, &pIB);
	if (FAILED(m_hr))
	{
		DXTRACE_MSG(L"Failed to create cylinder index buffer!");
		return false;
	}

	return pIB;
}

//----------------------------------------------------------------------------------------------
ID3D11Buffer* GeometryFactory::create_grid_vb(ID3D11Device* device, float width, float depth, UINT xseg, UINT zseg)
{
	GeometryGenerator::MeshData grid;
	m_geoGen.CreateGrid(width, depth, xseg, zseg, grid);
	UINT vertex_count = grid.Vertices.size();	// cache vertex count

	// Extract the vertex elements we are interested in.
	std::vector<BasicShader::Vertex> vertices(vertex_count);
	unsigned int k = 0;
	for (size_t i = 0; i < vertex_count; ++i, ++k)
	{
		vertices[k].Pos		= grid.Vertices[i].Position;
		vertices[k].Normal	= grid.Vertices[i].Normal;
		vertices[k].Tex		= grid.Vertices[i].TexC;
	}

	// Create vertex buffer.
	ID3D11Buffer* pVB;

	D3D11_BUFFER_DESC vbDesc;
	vbDesc.Usage			= D3D11_USAGE_IMMUTABLE;
	vbDesc.ByteWidth		= sizeof(BasicShader::Vertex) * vertex_count;
	vbDesc.BindFlags		= D3D11_BIND_VERTEX_BUFFER;
	vbDesc.CPUAccessFlags	= 0;
	vbDesc.MiscFlags		= 0;
	vbDesc.StructureByteStride = 0;

	D3D11_SUBRESOURCE_DATA vbData;
	vbData.pSysMem = &vertices[0];

	m_hr = device->CreateBuffer(&vbDesc, &vbData, &pVB);
	if (FAILED(m_hr))
	{
		DXTRACE_MSG(L"Failed to create grid vertex buffer!");
		return false;
	}

	return pVB;
}

//----------------------------------------------------------------------------------------------
ID3D11Buffer* GeometryFactory::create_grid_ib(ID3D11Device* device, float width, float depth, UINT xseg, UINT zseg)
{
	GeometryGenerator::MeshData grid;				// struct to store indices
	GeometryGenerator geoGen;						// object to generate indices
	geoGen.CreateGrid(width, depth, xseg, zseg, grid);

	UINT index_count = grid.Indices.size();			// cache index count

	std::vector<UINT> indices;
	indices.insert(indices.end(), grid.Indices.begin(), grid.Indices.end());
	
	ID3D11Buffer* pIB;								// index buffer to return

	D3D11_BUFFER_DESC ibDesc;
	ibDesc.Usage				= D3D11_USAGE_IMMUTABLE;
	ibDesc.ByteWidth			= sizeof(UINT) * index_count;
	ibDesc.BindFlags			= D3D11_BIND_INDEX_BUFFER;
	ibDesc.CPUAccessFlags		= 0;
	ibDesc.MiscFlags			= 0;
	ibDesc.StructureByteStride	= 0;
	
	D3D11_SUBRESOURCE_DATA idata;
	idata.pSysMem = &indices[0];

	m_hr = device->CreateBuffer(&ibDesc, &idata, &pIB);
	if (FAILED(m_hr))
	{
		DXTRACE_MSG(L"Failed to create grid index buffer!");
		return false;
	}

	return pIB;
}